﻿using System.Reflection;

namespace Foundation.Core
{
    public static class SelectCollectionServiceOptionsBuilderExtensions
    {
        #region //AddTypeKeyFactory 给类型自定义key

        /// <summary>
        /// 给类型 <paramref name="type"/> 自定义 key
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="type"></param>
        /// <param name="factory"></param>
        /// <returns></returns>
        public static SelectCollectionServiceOptionsBuilder AddTypeKeyFactory(this SelectCollectionServiceOptionsBuilder builder, Type type, Func<Type, string> factory)
        {
            builder.Registrar.AddTypeKeyFactory(type, factory);

            return builder;
        }

        /// <summary>
        /// 给类型 <paramref name="type"/> 自定义 key
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="builder"></param>
        /// <param name="factory"></param>
        /// <returns></returns>
        public static SelectCollectionServiceOptionsBuilder AddTypeKeyFactory<T>(this SelectCollectionServiceOptionsBuilder builder, Func<Type, string> factory)
        {
            builder.Registrar.AddTypeKeyFactory(typeof(T), factory);

            return builder;
        }

        /// <summary>
        /// 给类型 <paramref name="type"/> 自定义 key
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="builder"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static SelectCollectionServiceOptionsBuilder AddTypeKey<T>(this SelectCollectionServiceOptionsBuilder builder, string key)
        {
            builder.Registrar.AddTypeKeyFactory(typeof(T), (t) => key);

            return builder;
        }

        /// <summary>
        /// 给类型 <paramref name="types"/> 自定义 key
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="types"></param>
        /// <param name="factory"></param>
        /// <returns></returns>
        public static SelectCollectionServiceOptionsBuilder AddTypeKeyFactory(this SelectCollectionServiceOptionsBuilder builder, IList<Type> types, Func<Type, string> factory)
        {
            foreach (var t in types)
            {
                builder.Registrar.AddTypeKeyFactory(t, factory);
            }

            return builder;
        }

        #endregion //end of #region AddTypeKeyFactory 给类型自定义key

        #region //添加类型过滤器

        /// <summary>
        /// 添加允许类型过滤器
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public static SelectCollectionServiceOptionsBuilder AddTypeFilter(this SelectCollectionServiceOptionsBuilder builder, Func<Type, bool> filter)
        {
            builder.Registrar.AddTypeAllowFilter(filter);

            return builder;
        }

        #endregion //end of 添加类型过滤器

        #region //添加类型选项

        /// <summary>
        /// 查找添加类型选项集合
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="assembly"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public static SelectCollectionServiceOptionsBuilder AddTypeSelectitems(this SelectCollectionServiceOptionsBuilder builder, Assembly assembly, ISelectTypeFilter filter = null)
        {
            builder.AddTypeSelectitems(assembly.ExportedTypes, filter);

            return builder;
        }

        /// <summary>
        /// 查找添加类型选项集合
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="types"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public static SelectCollectionServiceOptionsBuilder AddTypeSelectitems(this SelectCollectionServiceOptionsBuilder builder, IEnumerable<Type> types, ISelectTypeFilter filter = null)
        {
            filter = filter ?? builder.TypeFilter;

            foreach (var t in types)
            {
                if (filter.IsAllowType(t))
                {
                    var key = filter.CreateKey(t);

                    if (!builder.IsExists(key, t))
                    {
                        builder.AddTypeOptions(key, t);
                    }
                }
            }

            return builder;

        }

        #endregion //end of 添加类型选项

        #region //自定义数据加载

        public static SelectCollectionServiceOptionsBuilder AddCustomItemsLoaderService(this SelectCollectionServiceOptionsBuilder builder, Assembly assembly, Type creatorOrFactory = null, ISelectCollectionCreator creator = null, Action<SelectCollectionCustomServiceLoderOptionsBuilder> optionsConfigure = null)
        {
            var flagType = typeof(ISelectItemsLoder);

            return builder.AddCustomItemsLoaderService(assembly.ExportedTypes.Where(t => t.IsClass && !t.IsAbstract && flagType.IsAssignableFrom(t)), creatorOrFactory, creator, optionsConfigure);
        }

        public static SelectCollectionServiceOptionsBuilder AddCustomItemsLoaderService(this SelectCollectionServiceOptionsBuilder builder, IEnumerable<Type> types, Type creatorOrFactory = null, ISelectCollectionCreator creator = null, Action<SelectCollectionCustomServiceLoderOptionsBuilder> optionsConfigure = null)
        {
            var flagType = typeof(ISelectItemsLoder);
            var category = SelectCategory.Custom;
            var isFactoryType = creatorOrFactory != null && typeof(ISelectCollectionCreatorFactory).IsAssignableFrom(creatorOrFactory);
            var isCreatorType = creatorOrFactory != null && typeof(ISelectCollectionCreator).IsAssignableFrom(creatorOrFactory);

            foreach (var type in types.Where(t => t.IsClass && !t.IsAbstract && flagType.IsAssignableFrom(t)))
            {
                var methods = type.GetMethods();

                foreach (var m in methods)
                {
                    var attr = m.GetCustomAttribute<SelectItemsMethodAttribute>();

                    if (attr == null || string.IsNullOrWhiteSpace(attr.Key)) continue;

                    if (builder.Store.IsExists(attr.Key, category))
                    {
                        //TODO:记录警告日志
                        continue;
                    }

                    if (m.ReturnType == typeof(void)) continue;

                    var parameters = m.GetParameters();
                    //if (parameters.Length > 1) continue;
                    int c = 0;
                    if (parameters.Length > 1
                        && ((c = parameters.Count(a => a.ParameterType == typeof(CancellationToken))) > 1 ||
                            (c == 1 && parameters[parameters.Length - 1].ParameterType != typeof(CancellationToken))
                            )
                        )
                    {
                        continue;
                    }

                    var isTask = m.ReturnType.IsGenericType && m.ReturnType.GetGenericTypeDefinition() == typeof(Task<>);

                    var returnType = isTask ? m.ReturnType.GetGenericArguments()[0] : m.ReturnType;

                    var enumerableType = returnType.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));

                    if (enumerableType == null) continue;

                    var itemType = enumerableType.GetGenericArguments()[0];

                    if (!typeof(ISelectItem).IsAssignableFrom(itemType)) continue;

                    var options = new SelectItemOptions(attr.Key, category);

                    options.Set(SelectCollectionConstant.ServiceMethodInfoKey, m);
                    options.CacheTime = attr.CacheMinutes > 0 ? TimeSpan.FromMinutes(attr.CacheMinutes) : TimeSpan.FromSeconds(0);

                    if (creator != null)
                    {
                        options.AddCreator(creator);
                    }
                    else if (isFactoryType) options.AddFactory(creatorOrFactory);
                    else if (isCreatorType) options.AddCreatorType(creatorOrFactory);
                    else
                    {
                        options.AddFactory<ServiceMethodSelectCollectionCreatorFactory>();
                    }

                    var methodOptions = new SelectItemLoadMethodOptions(m, attr);
                    options.SetMehtodOptions(methodOptions);

                    if (optionsConfigure != null)
                    {
                        var optionBuilder = new SelectCollectionCustomServiceLoderOptionsBuilder(options, type, m);

                        optionsConfigure(optionBuilder);
                    }

                    builder.Store.AddOptions(options);
                }
            }

            return builder;
        }

        #endregion //end of 自定义数据加载
    }
}
